/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * Project Name: lmrp-android app
 * Create Time: 16-2-16 下午6:45
 */

package com.lenovo.mso2o.util;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
import android.provider.Settings;
import android.support.v4.app.DialogFragment;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.mapapi.model.LatLng;
import com.github.lzyzsd.jsbridge.BridgeWebView;
import com.github.lzyzsd.jsbridge.CallBackFunction;
import com.lenovo.framework.FApplication;
import com.lenovo.framework.base.ActionBarFragmentActivity;
import com.lenovo.framework.base.FBaseActivity;
import com.lenovo.framework.base.InjectableFragmentActivity;
import com.lenovo.framework.biz.ContextManager;
import com.lenovo.framework.conf.FConstants;
import com.lenovo.framework.entity.FGson;
import com.lenovo.framework.entity.Res;
import com.lenovo.framework.rest.NetworkObserver;
import com.lenovo.framework.rx.RxBus;
import com.lenovo.framework.rx.RxUtils;
import com.lenovo.framework.service.LocationService;
import com.lenovo.framework.util.AppHelper;
import com.lenovo.framework.util.DLog;
import com.lenovo.framework.util.FPreferenceManager;
import com.lenovo.framework.util.FileHelper;
import com.lenovo.framework.util.TextHelper;
import com.lenovo.framework.util.maputil.MapDistance;
import com.lenovo.mso2o.MSApplication;
import com.lenovo.mso2o.R;
import com.lenovo.mso2o.conf.BizErrorCode;
import com.lenovo.mso2o.conf.ErrorCode;
import com.lenovo.mso2o.conf.HTTPMethod;
import com.lenovo.mso2o.conf.MSConstants;
import com.lenovo.mso2o.conf.OrderAction;
import com.lenovo.mso2o.entity.FAttachment;
import com.lenovo.mso2o.entity.FileRequest;
import com.lenovo.mso2o.entity.GrabResult;
import com.lenovo.mso2o.entity.H5PageRequest;
import com.lenovo.mso2o.entity.LocationEvent;
import com.lenovo.mso2o.entity.Order;
import com.lenovo.mso2o.entity.OrderUpdatingRequest;
import com.lenovo.mso2o.entity.UserSyncInfo;
import com.lenovo.mso2o.entity.g.AlarmTime;
import com.lenovo.mso2o.entity.g.AlarmTimeDao;
import com.lenovo.mso2o.rest.OrderAPI;
import com.lenovo.mso2o.rest.OtherAPI;
import com.lenovo.mso2o.rest.ServiceGenerator;
import com.lenovo.mso2o.rest.UserAPI;
import com.lenovo.mso2o.service.UploadService;
import com.lenovo.mso2o.ui.MainActivity;
import com.lenovo.mso2o.ui.WebActivity;
import com.lenovo.mso2o.ui.adapter.OrderAdapter;
import com.lenovo.mso2o.ui.adapter.VoicePlayClickListener;
import com.lenovo.mso2o.ui.fragment.DecoderFragment;
import com.lenovo.mso2o.ui.fragment.GuideFragment;
import com.lenovo.mso2o.ui.fragment.ImageFragment;
import com.lenovo.mso2o.ui.fragment.OrderGrabListFragment;
import com.lenovo.mso2o.ui.fragment.OrderListFragment;
import com.lenovo.mso2o.ui.fragment.OrderReceivingFragment;
import com.lenovo.mso2o.ui.fragment.POISearchDialogFragment;
import com.trello.rxlifecycle.ActivityEvent;
import com.trello.rxlifecycle.FragmentEvent;
import com.trello.rxlifecycle.components.support.RxFragment;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Scheduler;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.schedulers.Schedulers;

/**
 * Created by hippo on 11/2/15.
 */
public class ActionCallbacks {
    private static File logf;
    private static SimpleDateFormat df = new SimpleDateFormat("[yy-MM-dd hh:mm:ss]: ");
    private static Subscription _subscription;
    private static ServiceConnection connection;
    private static BDLocation mLocation;
    static final Subscription updateGrabSubscribtion[] = new Subscription[1];

    //get single file from camera/gallery
    public static Res chooseFile(Activity context) {
        //Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        //i.addCategory(Intent.CATEGORY_OPENABLE);
        //i.setType("*/*");
        //i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        //i.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
        //context.startActivityForResult(i, WebActivity.FILECHOOSER_RESULTCODE);
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        File root = Environment.getExternalStorageDirectory();
        intent.setDataAndType(Uri.fromFile(root), "video/*;audio/*;image/*;text/*");
        context.startActivityForResult(intent, WebActivity.FILECHOOSER_RESULTCODE);
        return null;
    }

    public static Res takePhoto(final WebActivity context, final CallBackFunction function, boolean isDir) {
        if (!isDir) {
            File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), AppHelper.packageName());
            // Create the storage directory if it does not exist
            if (!imageStorageDir.exists()) {
                imageStorageDir.mkdirs();
            }
            final File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
            Uri imageUri = Uri.fromFile(file);
            final Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            PackageManager pm = context.getPackageManager();
            if (pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0) {
                context.requestPermission(Manifest.permission.CAMERA, new Runnable() {
                    @Override
                    public void run() {
                        if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
                                != PackageManager.PERMISSION_GRANTED) {
                            context.showShortToast(R.string.allow_permission_request);
                        } else {
                            context.startActivityForResult(intent, WebActivity.TAKEPICTURE_REQUESTCODE);
                            WebActivity.res.setResult(file.getAbsolutePath());
                            //WebActivity.photoPath = file.getAbsolutePath();
                            WebActivity.res.setStatus(-1);
                        }
                    }
                });
                return null;
                /*context.startActivityForResult(intent, WebActivity.TAKEPICTURE_REQUESTCODE);
                WebActivity.res.setResult(file.getAbsolutePath());
                //WebActivity.photoPath = file.getAbsolutePath();
                WebActivity.res.setStatus(-1);*/
                //return WebActivity.res;
            } else {
                DLog.toast(context.getResources().getString(R.string.no_camera));
                WebActivity.res.setStatus(0);
                WebActivity.res.setMessage(context.getResources().getString(R.string.no_camera));
                function.onCallBack(FGson.gson().toJson(WebActivity.res));
            }
            return WebActivity.res;
        } else {
            //弹出选择获取图像方式列表。拍照和图库获取
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setSingleChoiceItems(new String[]{"拍照", "图库"}, 0, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    switch (which) {
                        case 0://拍照
                            File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), AppHelper.packageName());
                            // Create the storage directory if it does not exist
                            if (!imageStorageDir.exists()) {
                                imageStorageDir.mkdirs();
                            }
                            final File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
                            Uri imageUri = Uri.fromFile(file);
                            final Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                            PackageManager pm = context.getPackageManager();
                            if (pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0) {
                                context.requestPermission(Manifest.permission.CAMERA, new Runnable() {
                                    @Override
                                    public void run() {
                                        if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
                                                != PackageManager.PERMISSION_GRANTED) {
                                            context.showShortToast(R.string.allow_permission_request);
                                        } else {
                                            context.startActivityForResult(intent, WebActivity.TAKEPICTURE_REQUESTCODE);
                                            WebActivity.res.setResult(file.getAbsolutePath());
                                        }
                                    }
                                });
                            } else {
                                DLog.toast(context.getResources().getString(R.string.no_camera));
                                WebActivity.res.setStatus(0);
                                WebActivity.res.setMessage(context.getResources().getString(R.string.no_camera));
                                function.onCallBack(FGson.gson().toJson(WebActivity.res));
                            }
                            break;
                        case 1://图库
                            Intent intent_PIC = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                            intent_PIC.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                            PackageManager pm_PIC = context.getPackageManager();
                            if (pm_PIC.queryIntentActivities(intent_PIC, PackageManager.MATCH_DEFAULT_ONLY).size() > 0) {
                                context.startActivityForResult(intent_PIC, WebActivity.GET_PICTURE_FROMTHUMB_REQUESTCODE);
                            } else {
                                DLog.toast(context.getResources().getString(R.string.no_camera));
                                WebActivity.res.setStatus(0);
                                WebActivity.res.setMessage(context.getResources().getString(R.string.no_camera));
                                function.onCallBack(FGson.gson().toJson(WebActivity.res));
                            }
                            break;
                    }
                    dialog.dismiss();
                }
            }).show();
            return null;
        }
    }

    /*private static void saveLog(String log){
        logf = new File(Environment.getExternalStorageDirectory()
                + File.separator + "E-Support.txt");
        FileHelper.append(logf.getAbsolutePath(), df.format(new Date()) + "\n" + log);
    }*/
    //file use path
    public static Res postData(JSONObject gson, final WebActivity webActivity, final CallBackFunction callBackFunction) {
        try {
            final ArrayList<FAttachment> uploads = new ArrayList<>();
            JSONObject data = gson.getJSONObject("data");
            final JSONObject orig = data;
            try {
                if (data.getJSONObject("fields") != null) {
                    data = data.getJSONObject("fields");
                }
            } catch (JSONException e) {
                DLog.p(e);
            }
            LinkedHashMap<String, String> params = new LinkedHashMap<>();
            FileRequest fileRequest = new FileRequest();
            Iterator<String> keys = data.keys();
            boolean hasFile = false;
            while (keys.hasNext()) {
                String key = keys.next();
                try {
                    if (key.contains("original")) {
                        //Object object = data.get(key);
                        //if (object instanceof JSONArray) {
                        if (data.get(key) instanceof JSONArray) {
                            //JSONArray array = (JSONArray) object;
                            JSONArray array = (JSONArray) data.get(key);
                            for (int i = 0; i < array.length(); i++) {
                                FAttachment a = new FAttachment();
                                //file path
                                String path = array.getString(i);
                                fileRequest.getOriginal().add(path);
                                if (path.startsWith(BridgeWebView.LOCAL_FILE_SCHEMA)) {
                                    path = path.replace(BridgeWebView.LOCAL_FILE_SCHEMA, "");
                                }
                                //server need path with [?type] in the url
                                array.put(i, path);
                                //upload service use absolute path here
                                if (path.contains("?")) {
                                    path = path.substring(0, path.lastIndexOf("?"));
                                }
                                a.setPath(path);
                                uploads.add(i, a);
                                hasFile = true;
                            }
                        } else {
                            FAttachment a = new FAttachment();
                            //file path
                            //String path = object + "";
                            String path = (String) data.get(key);
                            fileRequest.getOriginal().add(path);

                            if (path.startsWith(BridgeWebView.LOCAL_FILE_SCHEMA)) {
                                path = path.replace(BridgeWebView.LOCAL_FILE_SCHEMA, "");
                            }

                            //server need path with [?type] in the url
                            data.put(key, path);

                            //upload service use absolute path here
                            if (path.contains("?")) {
                                path = path.substring(0, path.lastIndexOf("?"));
                            }
                            a.setPath(path);
                            uploads.add(a);
                            hasFile = true;
                        }
                    }
                    params.put(key, data.getString(key));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            final String url = "" + orig.getString("url");
            final String originUrl = url;
            final H5PageRequest request = new H5PageRequest();
            String ticketid = null;
            request.setFields(params);
            try {
                ticketid = orig.getString("ticketid");
            } catch (Exception e) {
                DLog.p(e);
            }
            try {
                webActivity.getIntent().putExtra("action", orig.getString("action"));
                request.setAction(orig.getString("action"));
            } catch (Exception e) {
                DLog.p(e);
            }
            try {
                request.setReason(orig.getString("reason"));
                webActivity.getIntent().putExtra("reason", orig.getString("reason"));

            } catch (Exception e) {
                DLog.p(e);
            }
            OtherAPI api = ServiceGenerator.createService(OtherAPI.class, MSConstants.APIConstants.APISERVER_ADDRESS + url.substring(1, 1 + url.lastIndexOf("/")));

            //params传值
            DLog.toast(MSConstants.APIConstants.APISERVER_ADDRESS + orig.getString("url").substring(1));
            Observable<Res<Object>> call = api.dynamicPostRx(url.substring(url.lastIndexOf("/") + 1), request);

            Observable<Res<String[]>> filecall = null;
            if (hasFile) {
                filecall = api.dynamicPostRxFile(url.substring(url.lastIndexOf("/") + 1), fileRequest);
            }
            String method = orig.getString("method");
            boolean map = false;
            try {
                map = orig.getBoolean("map");
            } catch (Exception e) {
            }
            if (method != null && !"".equals(method)) {
                if (HTTPMethod.DELETE.getValue().equals(method)) {
                    DLog.w("delete:", data.toString());
                    if (map) {
                        call = api.dynamicDeleteRx2(url.substring(url.lastIndexOf("/") + 1), request.getFields());
                    } else {
                        call = api.dynamicDeleteRx(url.substring(url.lastIndexOf("/") + 1), request);
                    }
                } else if (HTTPMethod.PUT.getValue().equals(method)) {
                    DLog.w("put:", data.toString());
                    if (map) {
                        call = api.dynamicPutRx2(url.substring(url.lastIndexOf("/") + 1), request.getFields());
                    } else {
                        call = api.dynamicPutRx(url.substring(url.lastIndexOf("/") + 1), request);
                    }
                } else {
                    if (map)
                        call = api.dynamicPostRx2(url.substring(url.lastIndexOf("/") + 1), request.getFields());
                }
            }
            if (OrderAction.GRAB.getValue().equals(request.getAction())) {
                OrderAPI orderAPI = ServiceGenerator.createService(OrderAPI.class);
                grabOrder(new Runnable() {
                              @Override
                              public void run() {
                                  webActivity.processPreview("正在抢单", null, false);
                              }
                          },
                        new Runnable() {
                            @Override
                            public void run() {
                                webActivity.processDismiss();
                            }
                        },
                        (Order) webActivity.getIntent().getSerializableExtra(WebActivity.ORDER), webActivity.getWebFragment(), orderAPI, Schedulers.newThread().createWorker()
                );
            } else {
                if (hasFile && filecall != null) {
                    final String finalTicketid = ticketid;
                    _subscription = filecall
                            // Started in onStart(), running until in onStop()
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .unsubscribeOn(Schedulers.io())
                            .doOnTerminate(new Action0() {
                                @Override
                                public void call() {
                                    _subscription = null;
                                }
                            })
                            .subscribe(new NetworkObserver<Res<String[]>>() {
                                @Override
                                public void onSuccess(Res<String[]> result) {
                                    if (result.getEcode() != 0) {
                                        ErrorCode bizErrorCode = BizErrorCode.errorMap.get(result.getEcode());
                                        if (bizErrorCode != null) {
                                            onFailure(bizErrorCode.getReason());
                                        } else {
                                            onFailure(webActivity.getString(R.string.unknown_error));
                                        }
                                        return;
                                    }
                                    result.setStatus(1);
                                    result.setData(result.getResult());
                                    int i = 0;
                                    for (FAttachment a : uploads) {
                                        a.setLazyId(result.getResult()[i++]);
                                        if (finalTicketid == null)
                                            a.setTicketid(((Order) webActivity.getIntent().getSerializableExtra(WebActivity.ORDER)).getTicketid());
                                        else
                                            a.setTicketid(finalTicketid);
                                        a.setAction(webActivity.getIntent().getStringExtra("action"));
                                    }
                                    if (uploads.size() > 0) {
                                        UploadService.actionLocalAttachInsert(webActivity, uploads);
                                    }
                                    webActivity.setResult(Activity.RESULT_OK);
                                    callBackFunction.onCallBack(FGson.gson().toJson(result));
                                }

                                @Override
                                public void onFailure(String tip) {
                                    DLog.w("result", tip);
                                    Res res = new Res();
                                    res.setStatus(0);
                                    res.setMessage(tip);
                                    String r = FGson.gson().toJson(res);
                                    webActivity.setResult(Activity.RESULT_CANCELED);
                                    callBackFunction.onCallBack(r);
                                }
                            });

                } else {
                    webActivity.processPreview("执行中", null, false);
                    /*if(originUrl != null) {
                        saveLog("\n" + "Send to: " + MSConstants.APIConstants.APISERVER_ADDRESS_STATIC + originUrl + "\n");
                    }else{
                        saveLog("\n" + "请求地址为空" + "\n");
                    }
                    String requestBody = "requstBody: " + "\n";
                    if(request != null){
                        requestBody += "action:" + request.getAction() + " reason:" + request.getReason() + "\n";
                        if(request.getFields() != null && request.getFields().size() > 0){
                            Set<String> fieldKeys = request.getFields().keySet();
                            for (String fieldKey : fieldKeys){
                                String fieldVal = request.getFields().get(fieldKey);
                                requestBody += "[" + fieldKey + "-" + fieldVal + "]" + "\n";
                            }
                        }
                        saveLog(requestBody + "\n");
                    }*/

                    _subscription = call
                            // Started in onStart(), running until in onStop()
                            .compose(webActivity.<Res<Object>>bindUntilEvent(ActivityEvent.PAUSE))
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .unsubscribeOn(Schedulers.io())
                            .doOnTerminate(new Action0() {
                                @Override
                                public void call() {
                                    _subscription = null;
                                }
                            })
                            .subscribe(new NetworkObserver<Res<Object>>() {
                                @Override
                                public void onSuccess(final Res<Object> result) {
                                    webActivity.processDismiss();
                                    if (result != null && result.getEcode() != 0) {
                                        //ErrorCode bizErrorCode = BizErrorCode.errorMap.get(result.getEcode());
                                        String reason = result.getReason();
                                        if (reason != null) {
                                            onFailure(reason);
                                        } else {
                                            onFailure(webActivity.getString(R.string.unknown_error));
                                        }
                                        return;
                                    }
                                    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(webActivity, "执行成功", Toast.LENGTH_SHORT).show();
                                            result.setStatus(1);
                                            result.setData(result.getResult());
                                            webActivity.setResult(Activity.RESULT_OK);
                                            callBackFunction.onCallBack(FGson.gson().toJson(result));
                                            //获取位置信息
                                            try {
                                                uploadInfoAsync(webActivity, orig.getString("url"));
                                            } catch (JSONException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                    }, 300);

                                    //如果是预约界面，则须将数据保存至数据库
                                    //逻辑: 将选择的预约时间 事前提醒时间 工单号 存入数据库
                                    //将来从数据库中作判断：若是到场的单 时间值在介于两个时间值之间 则发通知响铃 同时删除该工单
                                    //若当前时间值大于预约时间则删除它
                                    //从map中先拿到remindTime 和 appointment
                                    String remindTime = "";
                                    String appointment = "";
                                    if (request.getFields() != null && request.getFields().size() > 0) {
                                        for (String key : request.getFields().keySet()) {
                                            //remindTime  提前2小时提醒
                                            //appointment 2016-03-12 21:13:00
                                            if ("remindTime".equals(key)) {
                                                remindTime = request.getFields().get(key);
                                            }
                                            if ("pendingtime".equals(key) || "appointment".equals(key)) {
                                                appointment = request.getFields().get(key);
                                                DLog.i(key, appointment);
                                            }
                                        }
                                    }
                                    if (remindTime.length() > 0 && appointment.length() > 0) {
                                        try {
                                            String ticketid = (String) orig.get("ticketid");
                                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                                            Date mDate = sdf.parse(appointment);
                                            DLog.i(ticketid, mDate.toLocaleString());
                                            long deadtime1 = 0;
                                            long deadtime2 = mDate.getTime();
                                            if ("提前2小时提醒".equals(remindTime)) {
                                                deadtime1 = mDate.getTime() - 2 * 60 * 60 * 1000;
                                            } else if ("提前30分钟提醒".equals(remindTime)) {
                                                deadtime1 = mDate.getTime() - 30 * 60 * 1000;
                                            } else if ("提前4小时提醒".equals(remindTime)) {
                                                deadtime1 = mDate.getTime() - 4 * 60 * 60 * 1000;
                                            } else if ("提前1小时提醒".equals(remindTime)) {
                                                deadtime1 = mDate.getTime() - 60 * 60 * 1000;
                                            } else {
                                                //不提醒
                                                deadtime2 = -1;
                                            }
                                            if (deadtime2 > 0) {
                                                AlarmTimeDao alarmTimeDao = MSApplication.getDaoSession().getAlarmTimeDao();
                                                List<AlarmTime> list = alarmTimeDao.queryBuilder().where(AlarmTimeDao.Properties.Tickedid.eq(ticketid)).list();
                                                AlarmTime alarmTime = new AlarmTime();
                                                if (list != null && list.size() > 0) {
                                                    alarmTime = list.get(0);
                                                    alarmTime.setTickedid(ticketid);
                                                    alarmTime.setPretime(deadtime1);
                                                    alarmTime.setDeadtime(deadtime2);
                                                    alarmTime.setAlarminfo(remindTime);
                                                    DLog.i("appoint update", alarmTime.toString());
                                                    alarmTimeDao.update(alarmTime);
                                                } else {
                                                    alarmTime.setTickedid(ticketid);
                                                    alarmTime.setPretime(deadtime1);
                                                    alarmTime.setDeadtime(deadtime2);
                                                    alarmTime.setAlarminfo(remindTime);
                                                    DLog.i("appoint insert", alarmTime.toString());
                                                    alarmTimeDao.insert(alarmTime);
                                                }
                                            }
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }

                                @Override
                                public void onFailure(String tip) {
                                    DLog.w("result", tip);
                                    //saveLog("\n" + "请求失败 " + tip + "\n");
                                    webActivity.processDismiss();
                                    //Toast.makeText(webActivity, "执行失败", Toast.LENGTH_SHORT).show();
                                    Res res = new Res();
                                    res.setStatus(0);
                                    res.setMessage(tip);
                                    String r = FGson.gson().toJson(res);
                                    webActivity.setResult(Activity.RESULT_CANCELED);
                                    callBackFunction.onCallBack(r);
                                }
                            });
                }
            }
        } catch (JSONException e) {
            DLog.p(e);
        }
        return null;
    }

    public static Res scanQrCode(Activity context) {
        Intent intent = new Intent();
        intent.setClass(context, InjectableFragmentActivity.class);
        Bundle b = new Bundle();
        b.putString(InjectableFragmentActivity.FRAGMENT_CLASS_NAME, DecoderFragment.class.getName());
        intent.putExtras(b);
        context.startActivityForResult(intent, DecoderFragment.DECODER_REQUEST);
        return null;
    }

    public static Res openFile(final Activity activity, JSONObject object) {
        Res res = new Res();
        try {
            final Intent intent = new Intent(activity, ActionBarFragmentActivity.class);
            object = object.getJSONObject("data");
            String path = object.getString("path");
            if (path != null && path.contains(BridgeWebView.LOCAL_FILE_SCHEMA)) {
                path = path.replace(BridgeWebView.LOCAL_FILE_SCHEMA, "");
                intent.putExtra(ActionBarFragmentActivity.RIGHT_ACTIONBAR_ENABLE, true);
                intent.putExtra(ImageFragment.IS_REMOTE, false);
            }
            //将已经下载的cache作为本地文件进行展示
            if (path != null && path.startsWith("http")) {
                String local = FileCacheUtil.existLocalCache(path);
                intent.putExtra(ActionBarFragmentActivity.RIGHT_ACTIONBAR_ENABLE, false);
                if (local != null && new File(local).exists()) {
                    path = local;
                    intent.putExtra(ImageFragment.IS_REMOTE, false);
                } else {
                    intent.putExtra(ImageFragment.IS_REMOTE, true);
                }
            }
            if (path != null && !(path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".jpeg"))) {
                //TODO
                if (path.contains("http")) {
                    Uri uri = Uri.parse(path);
                    Intent it = new Intent(Intent.ACTION_VIEW, uri);
                    activity.startActivity(it);
                } else {
                    FileHelper.openFiles(path);
                }

                res.setStatus(1);
                return res;
            }
            intent.putExtra(ActionBarFragmentActivity.FRAGMENT_CLASS_NAME, ImageFragment.class.getName());
            intent.putExtra(ActionBarFragmentActivity.FRAGMENT_TITLE, R.string.browse_photo);
            intent.putExtra(ImageFragment.PATH, path);
            activity.startActivityForResult(intent, WebActivity.REQUEST_OPENFILE);
        } catch (JSONException e) {
            res.setStatus(0);
            res.setMessage(e.getMessage());
            return res;
        }
        return null;
    }

    public static Res callPhone(JSONObject object, Activity context) {
        Res res = new Res();
        try {
            JSONObject phone = object.getJSONObject("data");
            String number = phone.getString("phone");
            Intent intent = new Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", number, null));
            try {
                res.setStatus(1);
                context.startActivity(intent);
            } catch (Exception e) {
                res.setMessage(e.getMessage());
                res.setStatus(0);
            }
        } catch (JSONException e) {
            res.setMessage(e.getMessage());
            res.setStatus(0);
        }
        return res;
    }

    public static Res gotoPage(JSONObject object, WebActivity webActivity) {
        Res res = new Res();
        try {
            JSONObject data = object.getJSONObject("data");
            String url = data.getString("url");
            if (url.contains("android:-1")) {
                boolean retrieve = data.getBoolean("retrieve");
                if (!retrieve) {
                    webActivity.setResult(Activity.RESULT_OK);
                }
                res.setStatus(1);
                //删除WebActivity
                webActivity.finish();
            } else if (url.contains("android:history")) {
                res.setStatus(1);
                webActivity.setResult(Activity.RESULT_OK);
                List<Activity> activityList = FBaseActivity.getActivites();
                for (Activity a : activityList) {
                    if (a instanceof MainActivity) {
                        webActivity.setResult(Activity.RESULT_CANCELED);
                        ((MainActivity) a).onPageSelected(MainActivity.PAGE_HISTORY_ORDER, true);
                    } else {
                        ((FBaseActivity) a).setResult(Activity.RESULT_CANCELED);
                        ((FBaseActivity) a).defaultFinish();
                    }
                }
            } else if (url.contains("android:active")) {
                res.setStatus(1);
                webActivity.setResult(Activity.RESULT_OK);
                List<Activity> activityList = FBaseActivity.getActivites();
                for (Activity a : activityList) {
                    if (a instanceof MainActivity) {
                        webActivity.setResult(Activity.RESULT_CANCELED);
                        ((MainActivity) a).onPageSelected(MainActivity.PAGE_ACTIVE_ORDER, true);
                    } else {
                        ((FBaseActivity) a).setResult(Activity.RESULT_CANCELED);
                        ((FBaseActivity) a).defaultFinish();
                    }
                }
                RxBus rxBus = FApplication.getRxBus();
                rxBus.send(OrderListFragment.REFRESH_HISTORY_ORDER_LIST);
            } else if (url.contains("android:receive")) {
                res.setStatus(1);
                webActivity.setResult(Activity.RESULT_OK);
                List<Activity> activityList = FBaseActivity.getActivites();
                boolean begin = false;
                Activity main = null;
                for (Activity a : activityList) {
                    if (a instanceof MainActivity) {
                        begin = true;
                        main = a;
                    }
                    if (begin && !(a instanceof MainActivity)) {
                        a.finish();
                    }
                }
                if (main != null) {
                    Bundle bundle = new Bundle();
                    bundle.putInt(ActionBarFragmentActivity.FRAGMENT_TITLE, R.string.receive_order_pool);
                    bundle.putString(ActionBarFragmentActivity.FRAGMENT_CLASS_NAME, OrderReceivingFragment.class.getName());
                    bundle.putBoolean(ActionBarFragmentActivity.RIGHT_ACTIONBAR_ENABLE, true);
                    bundle.putBoolean(ActionBarFragmentActivity.BACK_REFRESHABLE, true);
                    Intent intent = new Intent(main, ActionBarFragmentActivity.class);
                    intent.putExtras(bundle);
                    main.startActivityForResult(intent, MSConstants.FragmentType.FRAGMENT_RECEIVEORDERS);
                }
            } else if (url.contains("android:grab")) {
                res.setStatus(1);
                webActivity.setResult(Activity.RESULT_OK);
                List<Activity> activityList = FBaseActivity.getActivites();
                boolean begin = false;
                Activity main = null;
                for (Activity a : activityList) {
                    if (a instanceof MainActivity) {
                        begin = true;
                        main = a;
                    }
                    if (begin && !(a instanceof MainActivity)) {
                        a.finish();
                    }
                }
                if (main != null) {
                    Bundle bundle = new Bundle();
                    bundle.putInt(ActionBarFragmentActivity.FRAGMENT_TITLE, R.string.grab_activity_title);
                    bundle.putString(ActionBarFragmentActivity.FRAGMENT_CLASS_NAME, OrderGrabListFragment.class.getName());
                    bundle.putBoolean(ActionBarFragmentActivity.RIGHT_ACTIONBAR_ENABLE, true);
                    bundle.putBoolean(ActionBarFragmentActivity.BACK_REFRESHABLE, true);
                    Intent intent = new Intent(main, ActionBarFragmentActivity.class);
                    intent.putExtras(bundle);
                    main.startActivityForResult(intent, MSConstants.FragmentType.FRAGMENT_GRABORDERS);
                }
            } else if (url.contains("android:0")) {
                res.setStatus(1);
                webActivity.setResult(Activity.RESULT_OK);
                webActivity.refresh();
            } else {
                Intent intent = new Intent(webActivity, WebActivity.class);
                try {
                    boolean retrieve = data.getBoolean("retrieve");
                    res.setStatus(1);
                    res.setMessage("" + retrieve);
                    intent.putExtra(FConstants.X5WEBVIEW_INITIAL_URL, MSConstants.APIConstants.APISERVER_ADDRESS + url.substring(1));
                    intent.putExtra(WebActivity.ORDER, webActivity.getIntent().getSerializableExtra(WebActivity.ORDER));
                    if (retrieve)
                        webActivity.startActivityForResult(intent, WebActivity.REQUEST_SUBPAGE_DATA);
                    else
                        webActivity.startActivityForResult(intent, WebActivity.REQUEST_STEP);
                } catch (Exception e) {
                    res.setStatus(0);
                    res.setMessage(e.getMessage());
                }
            }
        } catch (JSONException e) {
            res.setStatus(0);
            res.setMessage(e.getMessage());
            DLog.p(e);
        }
        return res;
    }

    public static Res autoSign(final JSONObject object, final WebActivity webActivity, final CallBackFunction function, final boolean tried) {
        final Res res = new Res();
        try {
            JSONObject dataObject = object.getJSONObject("data");
            final String ticketId = dataObject.getString("ticketId");
            final String longitude = dataObject.getString("longitude");
            final String latitude = dataObject.getString("latitude");
            if (TextHelper.isEmptyOrSpaces(longitude) || TextHelper.isEmptyOrSpaces(latitude)) {
                res.setStatus(0);
                res.setMessage(webActivity.getString(R.string.unknown_signplace));
                return res;
            }
            webActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    LatLng loc = tried ? LocationService.getRealTimeLatLngTimeless() : LocationService.getRealTimeLatLng();
                    if (loc != null) {
                        //自动签到
                        double dis = MapDistance.getInstance().getShortDistanceMeter(
                                Double.parseDouble(longitude),
                                Double.parseDouble(latitude),
                                loc.longitude, loc.latitude);
                        if (dis <= MSConstants.RADIS_MIN_SIGN) {
                            webActivity.processPreview(webActivity.getString(R.string.auto_sign), null, false);
                            OrderUpdatingRequest signRequest = new OrderUpdatingRequest();
                            //由于自动签到和手动签到要作区分，所以新给的参数{"fields":{"signtype":0}}表示自动签到
                            Map<String, Integer> mMap = new HashMap<>();
                            mMap.put("signtype", 0);
                            signRequest.setFields(mMap);
                            signRequest.setTicketid(ticketId);
                            signRequest.setAction(OrderAction.SIGININ.getValue());
                            ServiceGenerator.createService(OrderAPI.class).updateOrder(ticketId, OrderAction.SIGININ.getValue(), signRequest)
                                    // Started in onStart(), running until in onStop()
                                    .compose(webActivity.<Res>bindUntilEvent(ActivityEvent.DESTROY))
                                    .subscribeOn(Schedulers.io())
                                    .observeOn(AndroidSchedulers.mainThread())
                                    .unsubscribeOn(Schedulers.io())
                                    .doOnTerminate(new Action0() {
                                        @Override
                                        public void call() {
                                            webActivity.processDismiss();
                                        }
                                    })
                                    .subscribe(new NetworkObserver<Res>() {
                                        @Override
                                        public void onSuccess(Res result) {
                                            webActivity.processDismiss();
                                            if (result.getEcode() != 0) {
                                                ErrorCode bizErrorCode = BizErrorCode.errorMap.get(result.getEcode());
                                                if (bizErrorCode != null) {
                                                    onFailure(bizErrorCode.getReason());
                                                } else {
                                                    onFailure(webActivity.getString(R.string.unknown_error));
                                                }
                                                return;
                                            }
                                            result.setStatus(1);
                                            webActivity.setResult(Activity.RESULT_OK);
                                            function.onCallBack(FGson.gson().toJson(result));
                                            Toast.makeText(webActivity, "签到成功", Toast.LENGTH_SHORT).show();
                                        }

                                        @Override
                                        public void onFailure(String tip) {
                                            webActivity.processDismiss();
                                            DLog.w("result", tip);
                                            Res res = new Res();
                                            res.setStatus(0);
                                            res.setMessage(tip);
                                            String r = FGson.gson().toJson(res);
                                            webActivity.setResult(Activity.RESULT_CANCELED);
                                            function.onCallBack(r);
                                        }
                                    });
                        } else {
                            webActivity.processDismiss();
                            res.setStatus(-1);
                            res.setMessage(webActivity.getString(R.string.sign_faraway));
                            DLog.i("sign", FGson.gson().toJson(res));
                            function.onCallBack(FGson.gson().toJson(res));
                        }
                    } else {
                        webActivity.processDismiss();
                        if (tried && !CommonUtil.isGPSEnable(webActivity)) {
                            res.setStatus(0);
                            res.setMessage(webActivity.getString(R.string.no_fine_service_avalible));
                            function.onCallBack(FGson.gson().toJson(res));
                        } else {
                            if (!CommonUtil.isGPSEnable(webActivity)) {
                                Toast.makeText(webActivity, R.string.please_turn_on_gps, Toast.LENGTH_LONG).show();
                                Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                webActivity.startActivityForResult(myIntent, WebActivity.REQUEST_LOCATION);
                            } else {
                                //找不到位置，尝试重新定位
                                //定位失败，没有回调啊
                                if (!tried)
                                    webActivity.locateForSign(webActivity);
                            }
                        }
                    }
                }
            });
        } catch (JSONException e) {
            DLog.p(e);
            res.setStatus(0);
            res.setMessage(e.getMessage());
            function.onCallBack(FGson.gson().toJson(res));
        }
        return null;
    }

    public static Res openVoice(JSONObject object, final CallBackFunction function, final Context context) {
        final Res res = new Res();
        JSONObject data = null;
        try {
            data = object.getJSONObject("data");
            final String path = data.getString("path");
            if (path.startsWith("http")) {//网络地址

                FileCacheUtil.getFileFromWebOrLocal(path, new FileCacheUtil.FileLoadListener() {
                    @Override
                    public void onGotFile(File file) {
                        VoicePlayClickListener.playVoiceFile(file.getAbsolutePath(), function);
                    }

                    @Override
                    public void onFail(String error) {
                        res.setStatus(0);
                        res.setMessage(error);
                        function.onCallBack(FGson.gson().toJson(res));
                        Toast.makeText(context, error, Toast.LENGTH_LONG).show();
                    }

                    @Override
                    public void onProgress(int progress) {

                    }
                }, (Activity) context);


            } else {//本地数据
                if (path.contains(BridgeWebView.LOCAL_FILE_SCHEMA)) {
                    VoicePlayClickListener.playVoiceFile(path.replace(BridgeWebView.LOCAL_FILE_SCHEMA, ""), function);
                } else {
                    res.setStatus(0);
                    function.onCallBack(FGson.gson().toJson(res));
                }
            }
        } catch (JSONException e) {
            DLog.p(e);
            res.setStatus(0);
            res.setMessage(e.getMessage());
            function.onCallBack(FGson.gson().toJson(res));
        }

        return null;
    }

    public static Res navigation(LatLng start, JSONObject object, WebActivity webActivity) {
        try {
            Bundle bundle = new Bundle();
            JSONObject data = object.getJSONObject("data");
            String longitude = data.getString("longitude");
            String latitude = data.getString("latitude");
            DLog.d("navigation:", longitude + ":" + latitude);
            if (!TextUtils.isEmpty(longitude)) {
                bundle.putDouble(GuideFragment.END_LOG, Double.parseDouble(longitude));
            } else {
                //TODO for test!
                bundle.putDouble(GuideFragment.END_LOG, 116.397428);
            }
            if (!TextUtils.isEmpty(latitude)) {
                bundle.putDouble(GuideFragment.END_LAT, Double.parseDouble(latitude));
            } else {
                //TODO for test!
                bundle.putDouble(GuideFragment.END_LAT, 39.86923);
            }
            LatLng end = new LatLng(bundle.getDouble(GuideFragment.END_LAT), bundle.getDouble(GuideFragment.END_LOG));
            Utils.showChannelDialog(start, end, webActivity);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Res result = new Res();
        result.setStatus(1);
        return result;
    }


    public static Res search(JSONObject object, WebActivity webActivity) {
        Res res = new Res();
        try {
            JSONObject data = object.getJSONObject("data");
            String site = data.getString("type");
            DLog.d("search:", site);
            if (!TextUtils.isEmpty(site)) {
                DialogFragment search = new POISearchDialogFragment();
                Bundle b = new Bundle();
                b.putString(POISearchDialogFragment.TYPE_KEY, site);
                search.setArguments(b);
                search.show(webActivity.getSupportFragmentManager(), POISearchDialogFragment.TAG);
                return null;
            } else {
                res.setStatus(0);
                res.setMessage("search type not found!");
            }
        } catch (JSONException e) {
            res.setMessage(e.getMessage());
            res.setStatus(0);
            e.printStackTrace();
        }
        return res;
    }

    public static Res retrieveData(JSONObject object, WebActivity webActivity) {
        Intent intent = new Intent();
        Res res = new Res();
        try {
            intent.putExtra(WebActivity.PARENT_FUNCTION_NAME, object.getString("message"));
            intent.putExtra(WebActivity.PARENT_FUNCTION_DATA, object.getJSONObject("data").toString());
            DLog.w("retrieve", "message:" + object.getString("message") + " data:" + object.getJSONObject("data").toString());
            webActivity.setResult(Activity.RESULT_OK, intent);
            res.setStatus(1);
            webActivity.finish();
        } catch (JSONException e) {
            res.setStatus(0);
            res.setMessage(e.getMessage());
            DLog.p(e);
        }
        return res;
    }

    public static void grabOrder(Runnable pre, final Runnable post, final Order order, final RxFragment fragment, final OrderAPI orderAPI, final Scheduler.Worker worker) {
        if (_subscription != null && (!_subscription.isUnsubscribed())) {
            Toast.makeText(fragment.getContext(), "正在抢单...", Toast.LENGTH_SHORT).show();
        } else {
            pre.run();
            _subscription = orderAPI.updateOrder(order.getTicketid(), OrderAction.GRAB.getValue(), new OrderUpdatingRequest())
                    // Started in onStart(), running until in onStop()
                    .compose(fragment.<Res>bindUntilEvent(FragmentEvent.DESTROY))
                    .doOnTerminate(new Action0() {
                        @Override
                        public void call() {
                            _subscription = null;
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .unsubscribeOn(Schedulers.io())
                    .doOnTerminate(new Action0() {
                        @Override
                        public void call() {
                            RxUtils.unsubscribeIfNotNull(_subscription);
                            _subscription = null;
                        }
                    })
                    .subscribe(new NetworkObserver<Res>() {
                        @Override
                        public void onSuccess(Res result) {
                            DLog.w(getClass().getName(), "" + result);
                            if (result.getEcode() == 0) {
                                final int[] max = {3};
                                updateGrabSubscribtion[0] = worker.schedulePeriodically(new Action0() {
                                    @Override
                                    public void call() {
                                        DLog.w("schdule", "update grab" + order.toString());
                                        orderAPI.updateGrabRes(order.getTicketid())
                                                .compose(fragment.<Res<GrabResult>>bindUntilEvent(FragmentEvent.DESTROY))
                                                .subscribeOn(Schedulers.io())
                                                .observeOn(AndroidSchedulers.mainThread())
                                                .unsubscribeOn(Schedulers.io())
                                                .subscribe(new NetworkObserver<Res<GrabResult>>() {
                                                    @Override
                                                    public void onSuccess(Res<GrabResult> res) {
                                                        DLog.w("updated grab", res.toString());
                                                        if (res.getEcode() == 0 && res.getResult() != null) {
                                                            if (res.getResult().getSuccess() == 0) {
                                                                RxUtils.unsubscribeIfNotNull(updateGrabSubscribtion[0]);
                                                                updateGrabSubscribtion[0] = null;
                                                                //TODO
                                                                Toast.makeText(fragment.getContext(), "抢单失败", Toast.LENGTH_SHORT).show();
                                                                post.run();
                                                            } else if (res.getResult().getSuccess() == 1) {
                                                                Toast.makeText(fragment.getContext(), "抢单成功", Toast.LENGTH_SHORT).show();
                                                                //抢单成功，上传经纬度等信息
                                                                RxUtils.unsubscribeIfNotNull(updateGrabSubscribtion[0]);
                                                                updateGrabSubscribtion[0] = null;
                                                                RxBus rxBus = FApplication.getRxBus();
                                                                rxBus.send(order);
                                                                OrderAdapter.gotoAppointPage(fragment, order, res.getResult().getLink(), MSConstants.FragmentType.FRAGMENT_GRABORDERS);
                                                                post.run();
                                                            } else {
                                                                //抢单中
                                                                max[0]--;
                                                                if (max[0] <= 0) {
                                                                    RxUtils.unsubscribeIfNotNull(updateGrabSubscribtion[0]);
                                                                    updateGrabSubscribtion[0] = null;
                                                                    //TODO
                                                                    Toast.makeText(fragment.getContext(), "抢单失败", Toast.LENGTH_SHORT).show();
                                                                    post.run();
                                                                }
                                                            }
                                                        } else {
                                                            onFailure(res.getReason());
                                                        }
                                                    }

                                                    @Override
                                                    public void onFailure(String tip) {
                                                        RxUtils.unsubscribeIfNotNull(updateGrabSubscribtion[0]);

                                                        updateGrabSubscribtion[0] = null;
                                                        DLog.w("updated grab", tip);
                                                    }
                                                });
                                    }
                                }, 0, 3, TimeUnit.SECONDS);
                            } else {
                                onFailure(result.getReason());
                            }
                        }

                        @Override
                        public void onFailure(String tip) {
                            post.run();
                            Toast.makeText(fragment.getContext(), tip, Toast.LENGTH_LONG).show();
                        }
                    });
        }
    }

    public static void uploadInfoAsync(final Context mContext, final String operationType) {
        //工单编号，登录账号，操作类型（接单/抢单/预约/到场/完成/评价），经度，维度，APP操作时间，APP版本
        Intent intent = new Intent(ContextManager.context(), LocationService.class);
        connection = LocationService.connection(new LocationService.LocationSuccessListener() {
            @Override
            public void onReceiveLocation(BDLocation location) {
                mLocation = location;
                mContext.unbindService(connection);
            }
        }, intent);
        mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.currentThread().sleep(2000);
                    //组织好数据就开始上传
                    //工单编号：orderId
                    //登陆账号：
                    String username = FPreferenceManager.getString(MSConstants.ACCOUNT_USERNAME, "username error");
                    //操作类型：operationType
                    //经纬度：location
                    //app操作时间
                    //String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis()));
                    //app版本
                    PackageManager pm = mContext.getPackageManager();
                    String versionName = "";
                    try {
                        PackageInfo packageInfo = pm.getPackageInfo(mContext.getPackageName(), 0);
                        versionName = packageInfo.versionName;
                    } catch (PackageManager.NameNotFoundException e) {
                        e.printStackTrace();
                    }
                    if(mLocation == null){
                        uploadGPSAddress(operationType, versionName, 0, 0, username);
                    }else{
                        uploadGPSAddress(operationType, versionName, mLocation.getLatitude(), mLocation.getLongitude(), username);
                        mLocation = null;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private static void uploadGPSAddress(String action, String appversion, double lat, double longitude, String username){
        UserSyncInfo infoGps = new UserSyncInfo();
        infoGps.setAction(action);
        infoGps.setLoginname(username);
        infoGps.setLatitude(lat);
        infoGps.setLongitude(longitude);
        infoGps.setAppversion(appversion);
        Observable<Res> gpsObservable = ServiceGenerator.createService(UserAPI.class).uploadGPSInfo(username, infoGps);
        gpsObservable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .unsubscribeOn(Schedulers.io())
                .subscribe(new NetworkObserver<Res>() {
                    @Override
                    public void onSuccess(Res res) {
                        //成功不做处理
                    }

                    @Override
                    public void onFailure(String tip) {
                    }
                });
    }
}
